﻿using FirstLimitUpMode.Data;
using FirstLimitUpMode.Handles;
using FirstLimitUpMode.Models;
using FirstLimitUpMode.Views;
using GpCommon.Helpers;
using GpCommon.Logger;
using Newtonsoft.Json.Linq;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml.Linq;
using MethodTimer;
using System.Net.Http.Headers;
using GpCommon;
using GpCommon.Models;
using Newtonsoft.Json;
using GpCommon.CustomControl;
using System.Security.Policy;
using System.IO;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Drawing;
using System.Windows.Threading;
using System.Reflection;
using System.Timers;

namespace FirstLimitUpMode.ViewModels
{
    internal class MainVModel : BindableBase
    {
        private System.Threading.SynchronizationContext synContent = null;
        // 前某日涨停股
        private List<string> m_LastTdGPList = new List<string>();
        private List<Tuple<string, string>> m_AllGpList = new List<Tuple<string, string>>();

        //涨跌停封单量监控
        private List<GpTopVolumeEntity> m_TopVolumeList = new List<GpTopVolumeEntity>();
        private Dictionary<string, int> m_LastFstTopGpDic = new Dictionary<string, int>();

        public bool Is5More = false;
        public bool IsFstMode = true;
        private MainView m_View;
        private static MainVModel m_MainVModel;
        private bool m_ShowMsgBox = true;

        public BackgroundWorker m_Worker;

        private DateTime m_AutoLoadTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 15, 5, 0);

        #region Banding  属性
        private ObservableCollection<GpEntity> m_GPData;

        public ObservableCollection<GpEntity> GPData
        {
            get { return m_GPData; }
            set
            {
                m_GPData = value;
                this.RaisePropertyChanged(nameof(GPData));
            }
        }
        private GpEntity m_SelectedGp;

        public GpEntity SelectedGp
        {
            get { return m_SelectedGp; }
            set
            {
                m_SelectedGp = value;
                DataGridClickExecute();
                this.RaisePropertyChanged(nameof(SelectedGp));
            }
        }
        private float m_MinPrice = 2;

        public float MinPrice
        {
            get { return m_MinPrice; }
            set
            {
                m_MinPrice = value;
                this.RaisePropertyChanged(nameof(MinPrice));
            }
        }
        private float m_MaxPrice = 100;

        public float MaxPrice
        {
            get { return m_MaxPrice; }
            set
            {
                m_MaxPrice = value;
                this.RaisePropertyChanged(nameof(MaxPrice));
            }
        }

        private bool m_IsLockMode = true;

        public bool IsLockMode
        {
            get { return m_IsLockMode; }
            set
            {
                m_IsLockMode = value;
                this.RaisePropertyChanged(nameof(IsLockMode));
            }
        }
        private bool m_IsLockTime = true;

        public bool IsLockTime
        {
            get { return m_IsLockTime; }
            set
            {
                m_IsLockTime = value;
                this.RaisePropertyChanged(nameof(IsLockTime));
            }
        }
        private bool m_IsShow20 = true;

        public bool IsShow20
        {
            get { return m_IsShow20; }
            set
            {
                m_IsShow20 = value;
                this.RaisePropertyChanged(nameof(IsShow20));
            }
        }

        private bool m_IsShowMsg = false;

        public bool IsShowMsg
        {
            get { return m_IsShowMsg; }
            set
            {
                m_IsShowMsg = value;
                MessageView.IsShowMsg = value;
                this.RaisePropertyChanged(nameof(IsShowMsg));
            }
        }

        private bool m_IsAuto = false;

        public bool IsAuto
        {
            get { return m_IsAuto; }
            set
            {
                m_IsAuto = value;
                this.RaisePropertyChanged(nameof(IsAuto));
            }
        }

        private bool m_IsShowTrends = false;

        public bool IsShowTrends
        {
            get { return m_IsShowTrends; }
            set
            {
                m_IsShowTrends = value;
                m_View.trendCol.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
                this.RaisePropertyChanged(nameof(IsShowTrends));
            }
        }

        private string m_SearchGpText;

        public string SearchGpText
        {
            get { return m_SearchGpText; }
            set
            {
                m_SearchGpText = value;
                this.RaisePropertyChanged(nameof(SearchGpText));
            }
        }
        private float m_MinMarkUp = 5;

        public float MinMarkUp
        {
            get { return m_MinMarkUp; }
            set
            {
                m_MinMarkUp = value;
                this.RaisePropertyChanged(nameof(MinMarkUp));
            }
        }
        private int m_IntervalTop = 3;

        public int IntervalTop
        {
            get { return m_IntervalTop; }
            set
            {
                m_IntervalTop = value;
                m_LastTdGPList = InitLastDayTopData();
                this.RaisePropertyChanged(nameof(IntervalTop));
            }
        }
        private float m_BuyMarkUp = 5;

        public float BuyMarkUp
        {
            get { return m_BuyMarkUp; }
            set
            {
                m_BuyMarkUp = value;
                this.RaisePropertyChanged(nameof(BuyMarkUp));
            }
        }
        private bool m_IsBuyMarkUpEnable = true;

        public bool IsBuyMarkUpEnable
        {
            get { return m_IsBuyMarkUpEnable; }
            set
            {
                m_IsBuyMarkUpEnable = value;
                this.RaisePropertyChanged(nameof(IsBuyMarkUpEnable));
            }
        }
        private bool m_IsTopBuy = false;

        public bool IsTopBuy
        {
            get { return m_IsTopBuy; }
            set
            {
                m_IsTopBuy = value;
                IsBuyMarkUpEnable = !value;
                this.RaisePropertyChanged(nameof(IsTopBuy));
            }
        }
        private int m_RefreshFrequency = 1000;

        public int RefreshFrequency
        {
            get { return m_RefreshFrequency; }
            set
            {
                m_RefreshFrequency = value;
                this.RaisePropertyChanged(nameof(RefreshFrequency));
            }
        }

        public int BuyInValue
        {
            get { return TempData.CurValue; }
            set
            {
                TempData.CurValue = value;
                this.RaisePropertyChanged(nameof(BuyInValue));
            }
        }

        public float ValueLimit
        {
            get { return TempData.ValueLimit; }
            set
            {
                TempData.ValueLimit = value;
                this.RaisePropertyChanged(nameof(ValueLimit));
            }
        }
        #endregion

        public ICommand DataGridDoubleClickCommand { get; set; }
        public ICommand DataGridClickCommand { get; set; }
        public ICommand AddLockGpCommand { get; set; }
        public ICommand UpdateHistoryCommand { get; set; }

        public static MainVModel GetVModelInstance()
        {
            return m_MainVModel;
        }

        public MainVModel(MainView view)
        {

            try
            {
                if(SettingsHelper.Initialize())
                    InitData();
                InitCommand();
                m_View = view;
                synContent = System.Threading.SynchronizationContext.Current;

                // 更新股票数量
                GpNetDataHelper.GetGpTotalCount();

                m_LastTdGPList = InitLastDayTopData();
                m_LastFstTopGpDic = GpNetDataHelper.GetYesTopGps(DateTime.Now).Result;

                m_Worker = new BackgroundWorker();
                m_Worker.WorkerReportsProgress = true;
                m_Worker.ProgressChanged += Worker_ProgressChanged;
                m_Worker.RunWorkerCompleted += Worker_RunWorkerCompleted;


                var urls = UrlHelper.GetUrlForAllRealTimeMainData(1);
                List<GpEntity> ents = new List<GpEntity>();
                foreach (var url in urls)
                {
                    ents.AddRange(GetGPData(url).Result);
                }
                if(ents == null ||  ents.Count == 0)
                {
                    MessageBox.Show("初始化股票列表异常，将导致以名称添加自选股失败！");
                }
                else
                {
                    m_AllGpList.Clear();
                    ents.ForEach(x => m_AllGpList.Add(new Tuple<string, string>(x.Code, x.Name)));
                }

                // 设定到时自动更新历史数据
                if (m_AutoLoadTime > DateTime.Now)
                {
                    TimeSpan triggerTime = m_AutoLoadTime - DateTime.Now;
                    System.Timers.Timer loadTimer = new System.Timers.Timer(triggerTime.TotalMilliseconds);
                    loadTimer.Elapsed += (sender, e) =>
                    {
                        view.Dispatcher.Invoke(() =>
                        {
                            m_ShowMsgBox = false;
                            // 触发的方法
                            UpdateHistoryCommandExecute();
                        });

                        // 停止并释放定时器
                        loadTimer.Stop();
                        loadTimer.Dispose();
                    };

                    // 启动定时器
                    loadTimer.Start();
                }

                System.Threading.Thread thread = new System.Threading.Thread(() =>
                {
                    Stopwatch stopwatch = new Stopwatch();
                    while (view != null)
                    {
                        if (m_View.Visibility == Visibility.Hidden && !IsShowMsg)
                            continue;
                        stopwatch.Restart();
                        bool res = FlashData();

                        while (res && stopwatch.ElapsedMilliseconds < RefreshFrequency)
                        {
                            System.Threading.Thread.Sleep(50);
                        }
                        if (DateTime.Now.Hour == 23 && DateTime.Now.Minute == 30)
                            synContent.Post(CloseView, null);
                    }
                });
                thread.IsBackground = true;
                thread.Start();
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
            }
            m_MainVModel = this;
        }

        private void InitData()
        {
            MinPrice = SettingsHelper.GetFloatByName(SettingConfine.MIN_PRICE);
            MaxPrice = SettingsHelper.GetFloatByName(SettingConfine.MAX_PRICE);
            MinMarkUp = SettingsHelper.GetFloatByName(SettingConfine.MIN_MARKUP);
            IsLockMode = SettingsHelper.GetBoolByName(SettingConfine.SELECT_LOCK);
            IsLockTime = SettingsHelper.GetBoolByName(SettingConfine.TIME_LOCK);
            IsShow20 = SettingsHelper.GetBoolByName(SettingConfine.P20_SHOW);
            IntervalTop = SettingsHelper.GetIntByName(SettingConfine.INTERVAL_TOP);
            BuyMarkUp = SettingsHelper.GetFloatByName(SettingConfine.BUYING_MARKUP);
            RefreshFrequency = SettingsHelper.GetIntByName(SettingConfine.REFRESH_FREQUENCY);
            IsTopBuy = SettingsHelper.GetBoolByName(SettingConfine.IS_TOP);
            BuyInValue = SettingsHelper.GetIntByName(SettingConfine.BUYIN_VALUE);
            ValueLimit = SettingsHelper.GetFloatByName(SettingConfine.MIN_VALUE);
        }
        public void SaveData()
        {
            SettingsHelper.SetValue(SettingConfine.MIN_PRICE, MinPrice);
            SettingsHelper.SetValue(SettingConfine.MAX_PRICE, MaxPrice);
            SettingsHelper.SetValue(SettingConfine.MIN_MARKUP, MinMarkUp);
            SettingsHelper.SetValue(SettingConfine.SELECT_LOCK, IsLockMode);
            SettingsHelper.SetValue(SettingConfine.TIME_LOCK, IsLockTime);
            SettingsHelper.SetValue(SettingConfine.P20_SHOW, IsShow20);
            SettingsHelper.SetValue(SettingConfine.INTERVAL_TOP, IntervalTop);
            SettingsHelper.SetValue(SettingConfine.BUYING_MARKUP, BuyMarkUp);
            SettingsHelper.SetValue(SettingConfine.REFRESH_FREQUENCY, RefreshFrequency);
            SettingsHelper.SetValue(SettingConfine.IS_TOP, IsTopBuy);
            SettingsHelper.SetValue(SettingConfine.BUYIN_VALUE, BuyInValue);
            SettingsHelper.SetValue(SettingConfine.MIN_VALUE, ValueLimit);
        }
        private void InitCommand()
        {
            DataGridDoubleClickCommand = new DelegateCommand(DataGridDoubleClickExecute);
            DataGridClickCommand = new DelegateCommand(DataGridClickExecute);
            AddLockGpCommand = new DelegateCommand(AddLockGpCommandExecute);
            UpdateHistoryCommand = new DelegateCommand(UpdateHistoryCommandExecute);
        }
        private bool IsInValidTime = false;
        /// <summary>
        /// 实时刷新数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        public bool FlashData()
        {
            if(IsLockTime && (DateTime.Now.Hour < 10 
                || (DateTime.Now > new DateTime(DateTime.Now.Year,
                DateTime.Now.Month, DateTime.Now.Day, 13, 30, 0))))
            {
                IsInValidTime = true;
            }
            else
            {
                IsInValidTime = false;
            }

            try
            {
                int count = GpNetDataHelper.GetGpCountByFilter(MinPrice, MaxPrice, MinMarkUp, 5000).Result;
                var urls = UrlHelper.GetUrlForAllRealTimeMainData(2, 0, count);

                List<GpEntity> ents = new List<GpEntity>();
                foreach (var url in urls)
                {
                    ents.AddRange(GetGPData(url).Result);
                }
                if (ents == null || ents.Count <= 0)
                {
                    return false;
                }

                for (int i = 0; i < ents.Count; i++)
                {
                    if (TempData.OrderToBuyList.Contains(ents[i].Code))
                        ents[i].Status = 1;
                    if (ents[i].Status == 0 && TempData.WishGpList.Contains(ents[i].Code))
                    {
                        ents[i].Status = 2;
                    }
                    ents[i].IsLock = TempData.LockList.Contains(ents[i].Code);
                    if (ents[i].IsLock)
                    {
                        if (TempData.OrderToSaleList.Contains(ents[i].Code))
                        {
                            ents[i].Status = 1;
                        }
                        else
                        {
                            ents[i].Status = 0;
                        }
                        continue;
                    }
                    if (IsInValidTime)
                    {
                        ents.RemoveAt(i--);
                        continue;
                    }
                    if (!ents[i].Code.StartsWith("60") && !ents[i].Code.StartsWith("00"))
                    {
                        ents.RemoveAt(i--);
                        continue;
                    }
                    //if (Is5More)
                    //{
                    //    if(ents[i].CurPrice < 5)
                    //    {
                    //        ents.RemoveAt(i--);
                    //        continue;
                    //    }
                    //}
                    if (!IsFstMode)
                    {
                        if (!m_LastFstTopGpDic.ContainsKey(ents[i].Code)
                            || m_LastFstTopGpDic[ents[i].Code] > 1)
                        {
                            ents.RemoveAt(i--);
                            continue;
                        }
                    }
                    else
                    {
                        if (m_LastTdGPList.Contains(ents[i].Code))
                        {
                            ents.RemoveAt(i--);
                            continue;
                        }
                    }
                    //if (ents[i].CurPrice < MinPrice || ents[i].CurPrice > MaxPrice)
                    //{
                    //    ents.RemoveAt(i--);
                    //    continue;
                    //}
                    //if (ents[i].CurMarkUp < MinMarkUp)
                    //{
                    //    ents.RemoveAt(i--);
                    //    continue;
                    //}


                    if(ents[i].CurMarkUp > 9.8 && ents[i].CurAccer == 0)
                    {
                        ents.RemoveAt(i--);
                        continue;
                    }
                    if (DateTime.Now > new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 9, 30, 1))
                    {
                        if (ents[i].CurMarkUp > 9)
                        {
                            TempData.AddDayByDayGp(ents[i].Code);
                        }
                    }
                    if (TempData.RemoveList.Contains(ents[i].Code))
                    {
                        ents.RemoveAt(i--);
                        continue;
                    }
                    if(TempData.ValueLimit > 0 && ents[i].MoveValue <= TempData.ValueLimit)
                    {
                        ents.RemoveAt(i--);
                        continue;
                    }
                }

                if (!IsFstMode)
                {
                    ents = ents.OrderByDescending(x => x.CurMarkUp).ToList();
                }
                else
                {
                    ents = ents.OrderByDescending(x => x.CurAccer).ToList();
                }
                int lockCount = 0;
                if (IsLockMode)
                {
                    var lockList = ents.FindAll(x => x.IsLock);
                    lockCount = lockList.Count;
                    ents.RemoveAll(x => x.IsLock);
                    foreach (var item in TempData.LockList)
                    {
                        var temp = lockList.Find(x => x.Code == item);
                        if(temp != null)
                        {
                            ents.Insert(0, temp);
                        }
                        else
                        {
                            var curEnt = GpNetDataHelper.GetGpCurInfoByCode(item).Result;
                            if(curEnt != null)
                            {
                                temp = GpEntity.ConvertBy(curEnt);
                                temp.IsLock = true;
                                if (TempData.OrderToSaleList.Contains(item))
                                {
                                    temp.Status = 1;
                                }
                                else
                                {
                                    temp.Status = 0;
                                }
                                ents.Insert(0, temp);
                            }
                        }
                    }
                }
                int index = 1;
                ents.ForEach(x => x.Num = index++);
                if (IsShow20)
                {
                    if(ents.Count > lockCount + 20)
                        ents = ents.GetRange(0, lockCount + 20);
                    if (IsShowTrends)
                    {
                        ents.ForEach(x =>
                        {
                            var list = GpNetDataHelper.GetGpTrentsByCode(x.Code).Result;
                            x.LineImage = CreateSimpleLine(list, x.CurMarkUp >= 0);
                        });
                    }
                }

                
                for (int i = 0; i < ents.Count; i++)
                {
                    if (i > 30)
                        break;
                    // 行情监控
                    GpMarketMonitor(ents[i]);
                    // 一个月内涨停情况
                    GpHistoryTop(ents[i]);
                }
                if (IsAuto && !m_IsAutoBuying)
                {
                    AutoExecute(ents);
                }
                //m_View.SynContent.Post(UpdateGpData, ents);
                GPData = new ObservableCollection<GpEntity>(ents);
                //m_View.Dispatcher.Invoke(() =>
                //{
                //    m_View.GpDataGrid.ItemsSource = new ObservableCollection<GpEntity>(ents);
                //    //GPData = new ObservableCollection<GpEntity>(ents);
                //});
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                Logger.Error(ex);
                return false;
            }
            return true;
        }
        private void GpHistoryTop(GpEntity entity)
        {
            try
            {
                var list = GpLocalDataHelper.GetLocalHistoryDayInfoByCode(DateTime.Now.Year - 1, entity.Code);
                list.AddRange(GpLocalDataHelper.GetLocalHistoryDayInfoByCode(DateTime.Now.Year, entity.Code));

                int topNum = 0;
                int maxNum = 0;
                for (int i = list.Count - 1; i > 0; i--)
                {
                    if (i <= list.Count - 11)
                        break;
                    if (list[i].MarkUp >= 9.9)
                        topNum++;
                    if (list[i].HighPrice >= list[i - 1].ClsPrice * 1.099)
                        maxNum++;
                }
                entity.LastTopStr = topNum + "/" + maxNum;
            }
            catch (Exception ex)
            {

            }
        }
        /// <summary>
        /// 行情监控
        /// </summary>
        private void GpMarketMonitor(GpEntity entity)
        {
            // 涨停封单量监控
            if (entity.CurMarkUp > 9.8 && entity.CurAccer == 0)
            {
                Task.Run(() => TopVolumeDataCheck(entity,true));
            }
            // 跌停封单量监控
            else if(entity.CurMarkUp < -9.8 && entity.CurAccer == 0)
            {
                Task.Run(() => TopVolumeDataCheck(entity, false));
            }
            // 打开涨停监控
            else if(entity.CurAccer < 0 && entity.CurMarkUp - entity.CurAccer > 9.8)
            {
                MessageView.CreateMsg(entity.Code, entity.Name, MsgType.TopOpen);
            }
            // 打开跌停监控
            else if (entity.CurAccer > 0 && entity.CurMarkUp - entity.CurAccer < -9.8)
            {
                MessageView.CreateMsg(entity.Code, entity.Name, MsgType.BottomOpen);
            }
            // 急速拉升监控
            else if (entity.CurAccer >= 3)
            {
                MessageView.CreateMsg(entity.Code, entity.Name, MsgType.FastRise);
            }
            // 猛烈打压监控
            else if (entity.CurAccer <= -3)
            {
                MessageView.CreateMsg(entity.Code, entity.Name, MsgType.FastDrop);
            }
            // 涨停封板
            else if (entity.CurMarkUp > 9.8)
            {
                Task.Run(() => TopSealDataCheck(entity, true));
            }
            // 跌停封板
            else if (entity.CurMarkUp < -9.8)
            {
                Task.Run(() => TopSealDataCheck(entity, true));
            }
        }
        /// <summary>
        /// 涨跌停封单量监控
        /// </summary>
        /// <param name="tempEnt"></param>
        private void TopVolumeDataCheck(GpEntity tempEnt, bool isTop)
        {
            try
            {
                var detailEnt = GpNetDataHelper.GetGpCurInfoByCode(tempEnt.Code).Result;
                var tempPre = m_TopVolumeList.Find(x => x.GpCode == tempEnt.Code);
                if (detailEnt != null)
                {
                    if (tempPre == null)
                    {
                        GpTopVolumeEntity volumeEntity = new GpTopVolumeEntity();
                        volumeEntity.GpCode = tempEnt.Code;
                        volumeEntity.GpName = tempEnt.Name;
                        if (isTop)
                        {
                            volumeEntity.IsTop = isTop;
                            volumeEntity.GpVolume = detailEnt.Buy1Volume;
                            volumeEntity.Price = detailEnt.Buy1Price;
                        }
                        else
                        {
                            volumeEntity.IsTop = isTop;
                            volumeEntity.GpVolume = detailEnt.Sale1Volume;
                            volumeEntity.Price = detailEnt.Sale1Price;
                        }
                        m_TopVolumeList.Add(volumeEntity);
                        return;
                    }
                    else
                    {
                        //10%递减且金额超500万
                        if (isTop)
                        {
                            if (tempPre.GpVolume - detailEnt.Buy1Volume > tempPre.GpVolume * 0.1
                            && (tempPre.GpVolume - detailEnt.Buy1Volume) * 100 * detailEnt.Buy1Price > 5000000)
                            {
                                tempPre.GpVolume = detailEnt.Buy1Volume;
                                tempPre.Price = detailEnt.Buy1Price;
                                MessageView.CreateMsg(tempEnt.Code, tempEnt.Name, MsgType.VolumeDrop);
                            }
                        }
                        else
                        {
                            if (tempPre.GpVolume - detailEnt.Sale1Volume > tempPre.GpVolume * 0.1
                            && (tempPre.GpVolume - detailEnt.Sale1Volume) * 100 * detailEnt.Sale1Price > 5000000)
                            {
                                tempPre.GpVolume = detailEnt.Sale1Volume;
                                tempPre.Price = detailEnt.Sale1Price;
                                MessageView.CreateMsg(tempEnt.Code, tempEnt.Name, MsgType.VolumeDrop);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }
        private void TopSealDataCheck(GpEntity tempEnt, bool isTop)
        {
            try
            {
                var detailEnt = GpNetDataHelper.GetGpCurInfoByCode(tempEnt.Code).Result;
                if (detailEnt != null)
                {
                    if(isTop)
                    {
                        if(detailEnt.Sale1Volume == 0 && detailEnt.Buy1Volume != 0)
                        {
                            MessageView.CreateMsg(tempEnt.Code, tempEnt.Name, MsgType.TopSeal);
                        }
                    }
                    else 
                    {
                        if (detailEnt.Buy1Volume == 0 && detailEnt.Sale1Volume != 0)
                        {
                            MessageView.CreateMsg(tempEnt.Code, tempEnt.Name, MsgType.BottomSeal);
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }
        /// <summary>
        /// 获取实时数据
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        [Time]
        private async Task<List<GpEntity>> GetGPData(string url)
        {
            List<GpEntity> ents = new List<GpEntity>();
            try
            {
                Thread.Sleep(100);
                HttpResponseMessage response = await HttpHelper.Client.GetAsync(url).ConfigureAwait(false);

                if (response.IsSuccessStatusCode)
                {
                    response.EnsureSuccessStatusCode();
                    string htmlContent = response.Content.ReadAsStringAsync().Result;
                    if (!string.IsNullOrEmpty(htmlContent))
                    {
                        RootObject rootObj = JsonConvert.DeserializeObject<RootObject>(htmlContent);
                        if(rootObj != null)
                        {
                            CommonData.TotalGpCount = Convert.ToInt32(rootObj.data.total);
                            foreach (var item in rootObj.data.diff)
                            {
                                GpEntity ent = new GpEntity();
                                ent.Code = item.f12;
                                ent.Name = item.f14;
                                ent.CurPrice = CommonUtility.ToFloat(item.f2);
                                ent.CurMarkUp = CommonUtility.ToFloat(item.f3);
                                ent.CurAccer = CommonUtility.ToFloat(item.f22);
                                var totalValueTemp = (CommonUtility.ToFloat(item.f20) / 100000000.0f).ToString("F2");
                                ent.TotalValue = CommonUtility.ToFloat(totalValueTemp);
                                var moveValueTemp = (CommonUtility.ToFloat(item.f21) / 100000000.0f).ToString("F2");
                                ent.MoveValue = CommonUtility.ToFloat(moveValueTemp);
                                ents.Add(ent);
                            }
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
                Logger.Error("超时返回");
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
            }

            return ents;
        }
        /// <summary>
        /// 初始化三日内涨停数据
        /// </summary>
        private List<string> InitLastDayTopData()
        {
            List<string> result = new List<string>();

            try
            {
                DateTime tempTime = DateTime.Now;

                for (int i = 0; i < IntervalTop; i++)
                {
                    Tuple<int, List<GpEntity>> tuple = null;
                    int count = 0;
                    do
                    {
                        tempTime = tempTime.AddDays(-1);
                        tuple = GetTopData(tempTime).Result;
                        count++;
                    } while (tuple == null || tuple.Item2.Count <= 0 || count > 20);
                    if (tuple == null || tuple.Item2.Count <= 0)
                        return result;
                    tuple = GetTopData(tempTime, tuple.Item1).Result;
                    foreach (var item in tuple.Item2)
                    {
                        if (!result.Contains(item.Code))
                            result.Add(item.Code);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
            }
            return result;
        }

        /// <summary>
        /// 获取涨停数据
        /// </summary>
        /// <param name="day"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public async Task<Tuple<int, List<GpEntity>>> GetTopData(DateTime time, int count = 20)
        {
            string url = UrlHelper.GetUrlForTodayTopGps(time, count);

            Thread.Sleep(500);
            int size = 20;
            List<GpEntity> ents = new List<GpEntity>();
            try
            {
                HttpResponseMessage response = await HttpHelper.Client.GetAsync(url).ConfigureAwait(false);
                if (response.IsSuccessStatusCode)
                {
                    response.EnsureSuccessStatusCode();
                    string htmlContent = response.Content.ReadAsStringAsync().Result;
                    if (!string.IsNullOrEmpty(htmlContent))
                    {
                        JObject jobject = JObject.Parse(htmlContent);
                        if (string.IsNullOrEmpty(jobject["data"].ToString())) return null;
                        var childrens = jobject["data"]["pool"].Children();
                        string totalStr = jobject["data"]["tc"].ToString();
                        if (!string.IsNullOrEmpty(totalStr))
                        {
                            int.TryParse(totalStr, out size);
                        }

                        foreach (var item in childrens)
                        {
                            GpEntity ent = new GpEntity();
                            ent.Code = item["c"].ToString();
                            ent.Name = item["n"].ToString();
                            ent.CurPrice = float.TryParse(item["p"].ToString(), out float curPrice) ? curPrice / 1000.0f : 0.0f;
                            ent.CurMarkUp = float.TryParse(item["zdp"].ToString(), out float curMarkup) ? (float)Math.Round(curMarkup, 2, MidpointRounding.AwayFromZero) : 0.0f;
                            ents.Add(ent);
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            return new Tuple<int, List<GpEntity>>(size, ents);
        }



        #region 命令方法
        private void DataGridDoubleClickExecute()
        {
            try
            {
                if (SelectedGp != null)
                {
                    GpDetailInfoView m_DetailView = new GpDetailInfoView(SelectedGp.Code, BuyMarkUp, IsTopBuy);
                    m_DetailView.Owner = m_View;
                    m_DetailView.Show();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Logger.Error(ex);
            }
        }
        public void DataGridClickExecute()
        {
            try
            {
                if (SelectedGp != null)
                {
                    GpDetailInfoView m_DetailView = new GpDetailInfoView(SelectedGp.Code, BuyMarkUp, IsTopBuy);
                    m_DetailView.Owner = m_View;
                    m_DetailView.Closing += ReflashInfo;
                    m_DetailView.Show();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Logger.Error(ex);
            }
        }

        public void AddLockGpCommandExecute()
        {
            try
            {
                if (!string.IsNullOrEmpty(SearchGpText))
                {
                    string tempStr = SearchGpText;
                    SearchGpText = "";
                    if (int.TryParse(tempStr, out int tempCode))
                    {
                        if (TempData.LockList.Contains(tempStr))
                            return;
                        if (!m_AllGpList.Any(x => x.Item1 == tempStr))
                            return;
                        TempData.LockList.Add(tempStr);
                        TempData.WriteLockGps();
                        return;
                    }
                    var tempEnt = m_AllGpList.Find(x => x.Item2 == tempStr);
                    if (tempEnt != null)
                    {
                        if (!TempData.LockList.Contains(tempEnt.Item1))
                        {
                            TempData.LockList.Add(tempEnt.Item1);
                            TempData.WriteLockGps();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Logger.Error(ex);
            }
        }

        public void UpdateHistoryCommandExecute()
        {
            try
            {
                ClearWorkerHandler();
                m_Worker.DoWork += Worker_DoWork_LoadHis;
                m_Worker.RunWorkerAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 私有方法
        public static int HistoryGpNum;
        public static string InfoMsg;
        private void Worker_DoWork_LoadHis(object sender, DoWorkEventArgs e)
        {
            
            string rootPath = CommonData.HisInfoFolderPath;
            try
            {
                m_View.Dispatcher.Invoke(() => 
                {
                    m_View.ProgressRow.Height = new GridLength(30);
                });
                Task.Run(() =>
                {

                });
                try
                {
                    InfoMsg = "列表更新";
                    var urls = UrlHelper.GetUrlForAllRealTimeData();
                    List<GpEntity> ents = new List<GpEntity>();
                    foreach (var url in urls)
                    {
                        ents.AddRange(GetGPData(url).Result);
                    }
                    StringBuilder sbAll = new StringBuilder();
                    StringBuilder sbValid = new StringBuilder();

                    foreach (var item in ents)
                    {
                        string str = item.Code + ":" + item.Name;
                        sbAll.Append(str + ";");
                        if (CommonUtility.IsValidCode(item.Code, item.Name))
                            sbValid.Append(str + ";");
                    }
                    File.WriteAllText(CommonData.AllCodeFilePath, sbAll.ToString().TrimEnd(';'));
                    File.WriteAllText(CommonData.CodeFilePath, sbValid.ToString().TrimEnd(';'));

                    InfoMsg = "历史日线数据加载";
                    if (!Directory.Exists(rootPath))
                    {
                        Directory.CreateDirectory(rootPath);
                    }
                    int startYear = 1990; // 从1990开始
                    while (startYear <= DateTime.Now.Year)
                    {
                        if (!Directory.Exists(rootPath + "\\" + startYear))
                            Directory.CreateDirectory(rootPath + "\\" + startYear);
                        startYear++;
                    }
                    var codes = GpLocalDataHelper.GetValidGpCodes();
                    HistoryGpNum = codes.Count;
                    int index = 0;
                    ParallelOptions options = new ParallelOptions();
                    options.MaxDegreeOfParallelism = 10;
                    Parallel.ForEach(codes, options,
                        item =>
                        {
                            bool hasEx = false;
                            List<GpDayEntity> list = null;
                            do
                            {
                                try
                                {
                                    list = GpNetDataHelper.GetHistoryDayInfoByCode(item).Result;
                                    hasEx = false;
                                }
                                catch (AggregateException)
                                {
                                    hasEx = true;
                                }
                            } while (hasEx);


                            Dictionary<int, List<GpDayEntity>> dic = new Dictionary<int, List<GpDayEntity>>();

                            foreach (var day in list)
                            {
                                if (dic.ContainsKey(day.Time.Year))
                                {
                                    dic[day.Time.Year].Add(day);
                                }
                                else
                                {
                                    dic.Add(day.Time.Year, new List<GpDayEntity> { day });
                                }
                            }

                            foreach (var keyValue in dic)
                            {
                                var filePath = Path.Combine(rootPath, keyValue.Key.ToString(), keyValue.Value[0].Code + ".json");
                                //if (File.Exists(filePath)) continue;

                                StringBuilder stringBuilder = new StringBuilder();
                                foreach (var sub in keyValue.Value)
                                {
                                    stringBuilder.Append(sub.ToString() + ";");
                                }
                                if (stringBuilder.Length == 0) continue;

                                File.WriteAllText(filePath, stringBuilder.ToString());
                            }
                            index++;
                            m_Worker.ReportProgress(index * 100 / codes.Count, index);
                        });
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }

                if (m_ShowMsgBox)
                {
                    MessageBox.Show($"{InfoMsg}完成");
                }
                m_ShowMsgBox = true;
                m_View.Dispatcher.Invoke(() =>
                {
                    m_View.ProgressRow.Height = new GridLength(0);
                });

            }
            catch (Exception)
            {
                m_ShowMsgBox = true;
            }
        }
        private void ClearWorkerHandler()
        {
            m_Worker.DoWork -= Worker_DoWork_LoadHis;
        }

        private bool m_IsAutoBuying = false;
        private void AutoExecute(List<GpEntity> ents)
        {
            string code = "";
            foreach (var ent in ents)
            {
                if (ent.IsLock || ent.Status != 0)
                    continue;
                // 判断
                if (true)
                {
                    code = ent.Code;
                    break;
                }
            }
            if (!string.IsNullOrWhiteSpace(code))
            {
                double trigPrice = 0.0;
                double buyPrice = 0.0;
                int count = 0;
                m_IsAutoBuying = true;
                System.Threading.Thread thread = new System.Threading.Thread(() =>
                {
                    AutoHelper.BuyExecute(code, trigPrice, buyPrice, count);
                    m_IsAutoBuying = false;
                });
                thread.IsBackground = true;
                thread.Start();
            }
        }

        private void ReflashInfo(object sender, CancelEventArgs e)
        {
            BuyInValue = TempData.CurValue;
        }
        private void CloseView(object state)
        {
            this.m_View.Close();
        }
        private void UpdateGpData(object state)
        {
            GPData = new ObservableCollection<GpEntity>((List<GpEntity>)state);
        }


        /// <summary>
        /// 创建股票分时简图
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private ImageSource CreateSimpleLine(List<DetailEntity> list, bool isRed)
        {
            try
            {
                int width = 1000;
                int height = 300;

                var startIndex = list.FindIndex(x => x.EntTimeSpan.Hour == 9 && x.EntTimeSpan.Minute == 30);
                if (startIndex >= 0)
                {
                    list = list.GetRange(startIndex, list.Count - startIndex);
                }

                double maxMarkup = list.Max(x => x.MarkUp);
                double minMarkup = list.Min(x => x.MarkUp);

                if (minMarkup > 0)
                    minMarkup = 0;
                if (maxMarkup < 0)
                    maxMarkup = 0;

                // 点位间隔
                float filterNum = 5;
                // 边线间距
                int offset = 50;
                // 实际界面尺寸
                int tempHeight = height - 2 * offset;
                int tempWidth = width - 2 * offset;

                double preWidth = tempWidth / (240.0 / filterNum);
                List<System.Drawing.Point> points = new List<System.Drawing.Point>();
                List<System.Drawing.Point> pointLoop = new List<System.Drawing.Point>();
                int index = 0;
                for (int i = 0; i < list.Count; i++)
                {
                    if (i != 0 &&  i % filterNum != 0) continue;
                    double x = (index++) * preWidth;
                    double y = tempHeight - Math.Abs(list[i].MarkUp - minMarkup) / Math.Abs(maxMarkup - minMarkup) * tempHeight;
                    System.Drawing.Point pt = new System.Drawing.Point((int)(x + offset), (int)(y + offset));
                    points.Add(pt);
                    pointLoop.Add(pt);
                }

                int maxY = height - offset;
                int minY = points.Min(x => x.Y);
                System.Drawing.Point startP = points.First();
                System.Drawing.Point endP = points.Last();

                for (int i = 1; i < maxY - endP.Y; i++)
                {
                    pointLoop.Add(new System.Drawing.Point(endP.X, endP.Y + i));
                }
                for (int i = points.Count - 1; i >= 0; i--)
                {
                    pointLoop.Add(new System.Drawing.Point(points[i].X, maxY));
                }
                for (int i = 1; i < maxY - startP.Y; i++)
                {
                    pointLoop.Add(new System.Drawing.Point(startP.X, maxY - i));
                }

                System.Drawing.Point startPt0 = new System.Drawing.Point(0, (int)(tempHeight - Math.Abs(0 - minMarkup) / Math.Abs(maxMarkup - minMarkup) * tempHeight + offset));
                System.Drawing.Point endPt0 = new System.Drawing.Point(width, (int)(tempHeight - Math.Abs(0 - minMarkup) / Math.Abs(maxMarkup - minMarkup) * tempHeight + offset));
                using (Bitmap bitmap = new Bitmap(width, height))
                {
                    using (Graphics graphics = Graphics.FromImage(bitmap))
                    {
                        // 设置背景颜色
                        graphics.Clear(System.Drawing.Color.White);
                        //绘制填充

                        if(minY != maxY || maxMarkup != 0)
                        {
                            System.Drawing.Color fillColor = isRed ? System.Drawing.Color.FromArgb(255, 189, 189) : System.Drawing.Color.FromArgb(192, 255, 179);
                            System.Drawing.Drawing2D.LinearGradientBrush linBrush = new System.Drawing.Drawing2D.LinearGradientBrush(
                                new System.Drawing.Point(startP.X, minY),
                                new System.Drawing.Point(startP.X, maxY),
                                fillColor,
                                System.Drawing.Color.White
                                );
                            graphics.FillClosedCurve(linBrush, pointLoop.ToArray());
                        }

                        // 绘制一个折线
                        System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Gray, 8);
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;
                        graphics.DrawLine(pen, startPt0, endPt0);

                        System.Drawing.Color lineColor = isRed ? System.Drawing.Color.Red : System.Drawing.Color.Green;

                        pen = new System.Drawing.Pen(lineColor, 10);
                        graphics.DrawLines(pen, points.ToArray());


                        // 将图像保存到内存流
                        using (MemoryStream ms = new MemoryStream())
                        {
                            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                            ms.Seek(0, SeekOrigin.Begin);

                            // 使用BitmapImage加载图像
                            BitmapImage bi = new BitmapImage();
                            bi.BeginInit();
                            bi.StreamSource = ms;
                            bi.CacheOption = BitmapCacheOption.OnLoad; // 加载后立即缓存整个图像
                            bi.EndInit();
                            bi.Freeze();
                            return bi;
                        }
                    }
                }
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion

        #region 进度条相关
        private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            m_View.progressBar.Value = e.ProgressPercentage;

            int currentTask = (int)e.UserState;
            m_View.barText.Text = $"正在{InfoMsg}（{currentTask}/{HistoryGpNum}）";
        }
        private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            m_View.progressBar.Value = 0;
            m_View.barText.Text = "";
        }
        #endregion
    }
}
